/*
 * ServerThread.cpp
 *
 * Author: Grupo Nro.
 */

#include "ServerThread.h"
#include "ProtocoloServidor.h"
#include "Box.h"
#include "EnemySpawner.h"
#include "MetalWall.h"
#include "CampaniaXml.h"
#include "SharedConstants.h"

ServerThread::ServerThread(Mutex * mutex, ServerSocket * serverSocket,
		ServerSocket * serverSocketEnvio) {
	this->mutex = mutex;
	this->serverSocket = serverSocket;
	this->serverSocketEnvio = serverSocketEnvio;
	this->morir = false;
	IDPartidaSecuencia = 1000;
	players_id_counter = 1;
}

ServerThread::~ServerThread() {
	std::size_t i;
	for (i = 0; i < this->jugadoresConectados.size(); i++) {
		JugadorConectado * jugadorConectado = jugadoresConectados[i];
		delete jugadorConectado;
		jugadorConectado = NULL;
	}
	for (i=0; i < campaniasDisponibles.size(); i++) {
	    delete campaniasDisponibles[i];
	}
	for (i=0; i < partidasEnCurso.size(); i++) {
	    partidasEnCurso[i]->stop();
	    partidasEnCurso[i]->join();
	    delete partidasEnCurso[i];
	}
}

void ServerThread::run() {
	bootstrap();
	this->serverSocket->conectar();
	this->serverSocketEnvio->conectar();

	int sockfdCliente = -1;
	int sockfdClienteSend = -1;
	while (!this->morir) {
		try {
			sockfdCliente = this->serverSocket->aceptarConexion();
			ProtocoloServidor::send_requestForUpdates(sockfdCliente, "OK");
			sockfdClienteSend = this->serverSocketEnvio->aceptarConexion();

			JugadorThreadRecepcion * proceso = new JugadorThreadRecepcion(
					this->mutex, sockfdCliente);
			JugadorThreadEnvio * procesoEnvioEventos = new JugadorThreadEnvio(
					this->mutex, sockfdClienteSend);
			JugadorConectado * jugadorConectado = new JugadorConectado(
			        players_id_counter++, proceso, procesoEnvioEventos, this);
			this->mutex->lock();
			this->jugadoresConectados.push_back(jugadorConectado);
			this->mutex->unlock();

			jugadorConectado->start();
		} catch (ComunicacionException & e) {
			cerr << e.error() << std::endl;
		}
	}
}

void ServerThread::finalizar() {
	//Morir jugadores
	std::size_t i;
	for (i = 0; i < jugadoresConectados.size(); i++) {
		JugadorConectado * jugadorConectado = jugadoresConectados[i];
		jugadorConectado->terminar();
	}
}

vector<JugadorConectado *> & ServerThread::getJugadoresConectados() {
	return this->jugadoresConectados;
}

void ServerThread::agregarNuevaPartida(Partida* p) {
	this->mutex->lock();
	partidasEnCurso.push_back(p);
	this->mutex->unlock();
}

vector<Campania*> ServerThread::getCampanias() {
	return campaniasDisponibles;
}

void ServerThread::bootstrap() {
    CampaniaXml campaign_loader;
    campaniasDisponibles = campaign_loader.getCampanias();
}

int ServerThread::getSiguienteIDPartida() {
	return (++IDPartidaSecuencia);
}

vector<Partida*> ServerThread::getPartidasExistentes() {
	return partidasEnCurso;
}

Partida* ServerThread::getPartidaPorID(int id) {
	vector<Partida *>::iterator it;
	for (it = partidasEnCurso.begin(); it != partidasEnCurso.end(); ++it) {
		if ((*it)->getId()==id){
			return *it;
		}
	}
	return NULL;
}
